/*
The MIT License (MIT)

Copyright (c) 2013 Mike Dapiran, Brian May, Richard Pospesel, and Bert Wierenga

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software 
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once

#include "hhdICollisionObject.h"
#include "hhdCollisionShape.h"

#include "btBulletCollisionCommon.h"
#include "btBulletDynamicsCommon.h"

#include "hhdRegistry.h"

namespace hhd
{
	namespace BulletPhysics
	{
		class BulletPhysicsDirector;
		class HogsheadMotionState;

		/**
		A RigidBody Component extends ICollisionObject and requires a sibling CollisionShape component in the 
		GameObject tree.  There are three types of RigidBodies: Static, Kinematic and Dynamic.  GameObjects
		with RigidBody Components can interact with other RigidBody having GameObjects.  By default, RigidBody
		is assumed to be Static.  It is assumed there is only one RigidBody or one TriggerVolume component on a single 
		GameObject.  On collision with another RigidBody or TriggerVolume, a CollisionMessage will be sent with a list
		of contat points.
		@see RigidBodyType
		**/
		class RigidBody : public ICollisionObject
		{
			CollisionObjectH(hhd::BulletPhysics::RigidBody, RigidBody);
			HHD_REGISTRANT_H(IComponent, RigidBody);

		public:
			RigidBody();
			~RigidBody();
			void initialize();
			IComponent* readXML(const String& in_xml);
			void update(const GameTimer&);
			Vector3 getVelocity() const;
			Vector3 getPosition() const;
			Quaternion getOrientation() const;

			inline float getFriction() const
			{
				return _friction;
			}

			inline RigidBodyType getType() const
			{
				return _type;
			}

			inline const Vector3& getMaxPiecewiseSpeed() const
			{
				return  _max_piecewise_speed;
			}
			Vector3 getExtents() const;
		private:

			// activation methods
			void onSetActive();
			void onSetInactive();

			friend class BulletPhysicsManager;

			// messaging callbacks
			static void handle_apply_transform_message(IMessageReceiver*,IMessage*);
			static void handle_apply_velocity_message(IMessageReceiver*,IMessage*);
			static void handle_apply_impulse_message(IMessageReceiver*,IMessage*);
			static void handle_set_force_message(IMessageReceiver*,IMessage*);
			static void handle_set_friction_message(IMessageReceiver*,IMessage*);
			static void handle_set_restitution_message(IMessageReceiver*,IMessage*);
			static void handle_set_dampening_message(IMessageReceiver*,IMessage*);
			static void handle_set_max_speed_message(IMessageReceiver*,IMessage*);
			static void handle_set_gravity_enabled_message(IMessageReceiver*, IMessage*);
			// keeps Kinematic objects from penetrating Static objcts
			static void handle_collision_message(IMessageReceiver*,IMessage*);

			static void handle_set_activity(IMessageReceiver*, IMessage*);

			static void handle_set_group_mask(IMessageReceiver*, IMessage*);

			RigidBodyType _type;
			String _type_string;

			/** Physical Constants **/
			/** Defines the mass of the RigiBody object **/
			float _mass;	/** The mass of an object **/
			float _friction; /** The friction of the object **/
			float _restitution; /** The bounciness of the object **/
			Vector3 _angular_factor;	/** Dampening of rotation about global axes **/
			Vector3 _linear_factor;	/** Dampening of translation down global axes **/
			float _max_speed;	/** The maximum speed this rigid body can move **/
			Vector3 _max_piecewise_speed; /** The axis-wise max speeds this rigid body ca move **/
			Vector3 _global_force;	/** Additional global force to apply on each frame **/
			Vector3 _local_force;	/** Additinal local force to apply on each frame **/
			Vector3 _global_torque;  /** Additional global torque to apply on each frame **/
			Vector3 _local_torque;	/** Additional local torque to apply on each frame **/
			bool _gravity_enabled;	/** When set to true, this RigidBody is affected by gravity **/

			// the underlying rigidbody object for bullet
			btRigidBody* _rigid_body;
			// our collision shape component
			
			// this guy syncs bullet's and hogshead's transforms
			HogsheadMotionState* _motion_state;

			// pointer to the director
			BulletPhysicsDirector* _bullet_director;

			int _previous_mask;
		};
	}
}
